#include "area_reader.h"


/* default constructor
*/
area_reader::area_reader()
{
}

/* 
 *	initialize area_reader 
 *	open bin file and access mdb for the area variable setting
 */
area_reader::area_reader(char *HourlyBinFile, char *SummaryBinFile, char *dbFile)
	: reader(HourlyBinFile, dbFile)
{
	summary_file_Handle = open(SummaryBinFile, O_BINARY);
	if (summary_file_Handle >0) 
	{
		printf ("Open %s succeeded.\n", SummaryBinFile);
	}
	else 
	{
		printf ("Failed Open %s.\n", SummaryBinFile);
		switch (errno) 
		{
			case EACCES:  printf ("Permission denied.\n"); break;
			case EMFILE:  printf ("No file handle available.\n"); break;
			case ENOENT:  printf ("File or path not found.\n"); break;
			default:      printf ("Unknown error.\n"); break;
		}
	}

	try
	{
		CRecordset rs(&db);
		/* READ AREA Ancillary Service Type Index */
		rs.Open(CRecordset::forwardOnly, _T(GET_AREA_ANC_INDEX_SQL));
		rs.GetFieldValue("VALUE", area_anc_setting);
		readAncSetting(area_anc_setting);
		rs.Close();

		/* READ NUMBER OF EMISSION From DB, Yanli Wei, 06/10/2010 */
		rs.Open(CRecordset::forwardOnly, _T(GET_AREA_EMISSION_COUNT_SQL));
		rs.GetFieldValue("NUM_EMI", area_emssions_count);
		readEmssionsCount(area_emssions_count);
		rs.Close();

		/* READ EMISSION OPTION FROM DB, Yanli Wei, 06/10/2010*/
		rs.Open(CRecordset::forwardOnly, _T(GET_AREA_EMISSION_SETTING_SQL));
		rs.GetFieldValue("VALUE", area_emssions_option);
		readEmssionsOption(area_emssions_option);
		rs.Close();

		/* READ EMISSION TYPES FROM DB, Yanli Wei, 06/10/2010*/
        readEmissionType();

		/* READ AREA VARIABLE SETTING*/
		rs.Open(CRecordset::forwardOnly, _T(GET_AREA_VAR_SQL));
		rs.GetFieldValue("VALUE", area_var_setting);
		num_vars = 0;
		read_area_var_setting(&area_var_setting);
		rs.Close();
		
		/* READ TOTAL NUMBER OF AREAERATOR FROM Hourly BINARY File*/
		read_area_num(file_Handle, &hourly_num_area);

		/* READ ALL AREAERATOR INFO FROM Hourly BINARY File*/
		read_area_info(file_Handle, &hourly_num_area, &hourly_area_info_list, &hourly_area_index_map);
	}
	catch (CDBException *p)
	{
		printf("%s\n", p->m_strError);
	}

}
/*
 *	read number of area from binary file
 */
void area_reader:: read_area_num(int f_handle, long * num)
{
	lseek(file_Handle, NUM_AREA_OFFSET, SEEK_SET);
	read(file_Handle, num, sizeof(num));
	cout<<"total "<<*num<<endl;
}

/*
 *	return number of area
 */
long area_reader::get_num_area() 
{
	return hourly_num_area;
}

/*
 *	read ancillary service setting, Yanli Wei, 06/10/2010
 */
void area_reader::readAncSetting(CString ancIndex)
{
	num_ancs=0;
	int i, j;
	for (i=0; i< (ancIndex.GetLength()); i++)
	{	
		_stscanf(ancIndex.Mid (i, 1), _T("%d"), &j);
		switch (i)
			{
				case 0:		if (j) {
							AS_type_list.push_back("Regulation Down");
							num_ancs++;
							}
							break;
				case 1:		if (j) {
							AS_type_list.push_back("Regulation Up");
							num_ancs++;;
							}
							break;
				case 2:		if (j) {
							AS_type_list.push_back("Spinning Reserve");
							num_ancs++;;
							}
							break;
				case 3:		if (j) {
							AS_type_list.push_back("Non-Spinning Reserve");
							num_ancs++;;
							}
							break;
				case 4:		if (j) {
							AS_type_list.push_back("Replacement Reserve");
							num_ancs++;;
							}
							break;
		}
	}
}

/*
 *	return emissions option, Yanli Wei, 06/10/2010
 */
void area_reader::readEmssionsOption(CString area_emssions_option)
{
		emissions_option = atoi(area_emssions_option); 
}

/*
 *	return number of emissions, Yanli Wei, 06/10/2010
 */
void area_reader::readEmssionsCount(CString area_emssions_option)
{
		num_emissions = atoi(area_emssions_option);

}

/*
 *  Read emission types, Yanli Wei, 06/10/2010
 */
void area_reader::readEmissionType()
{
	CString emissionType;
	CRecordset rs(&db);
	rs.Open(CRecordset::forwardOnly, _T(GET_AREA_EMISSION_NAME_SQL));
	while ( !rs.IsEOF() ) 
	{
		rs.GetFieldValue("NAME", emissionType);
		emission_type_list.push_back(emissionType);
		rs.MoveNext();
	}
	rs.Close();
}

/*
 *	read current area output variable setting
 *	and store setting into a string vector:area_var_list
 */
void area_reader::read_area_var_setting (CString * area_var_setting)
{
	CString output;
	int i=0, j=0;
		for (i=0; i< (area_var_setting->GetLength()); i++)
		{
			_stscanf(area_var_setting->Mid (i, 1), _T("%d"), &j);
			switch (i)
			{
				case 0:		if (j) {
								area_var_list.push_back("Avg LMP Weighted by Gen ($/MWh)");
								var_index_map.insert(make_pair("Avg LMP Weighted by Gen ($/MWh)", ++num_vars));
							}
							break;

				case 1:		if (j) {
								area_var_list.push_back("Avg LMP Weighted by Load ($/MWh)");
								var_index_map.insert(make_pair("Avg LMP Weighted by Load ($/MWh)", ++num_vars));
							}
							break;

				case 2:		if (j) {
								area_var_list.push_back("Avg LMP Weighted by Energy ($/MWh)");	
								var_index_map.insert(make_pair("Avg LMP Weighted by Energy ($/MWh)", ++num_vars));
							}
							break;

				case 3:		if (j) {
								area_var_list.push_back("Simple Average LMP ($/MWh)");	
								var_index_map.insert(make_pair("Simple Average LMP ($/MWh)", ++num_vars));
							}
							break;

				case 4:		if (j) {
								area_var_list.push_back("Generation (MWh)");
								var_index_map.insert(make_pair("Generation (MWh)", ++num_vars));
							}
							break;

				case 5:		if (j) {
								area_var_list.push_back("Generation Revenue (k$)");
								var_index_map.insert(make_pair("Generation Revenue (k$)", ++num_vars));
							}
							break;

				case 6:		if (j) {
								area_var_list.push_back("Served Load (MWh)");
								var_index_map.insert(make_pair("Served Load (MWh)", ++num_vars)); 
							}
							break;

				case 7:		if (j) {
								area_var_list.push_back("Load Payment (k$)");
								var_index_map.insert(make_pair("Load Payment (k$)", ++num_vars));
							}
							break;

				case 8:		if (j) {
								area_var_list.push_back("Unserved Load (MWh)");
								var_index_map.insert(make_pair("Unserved Load (MWh)", ++num_vars));
							}
							break;

				case 9:		if (j) {
								area_var_list.push_back("Unserved Load Cost (k$)");
								var_index_map.insert(make_pair("Unserved Load Cost (k$)", ++num_vars));
							}
							break;

				case 10:	if (j) {
								area_var_list.push_back("Load (MWh)");
								var_index_map.insert(make_pair("Load (MWh)", ++num_vars));
							}
							break;

				case 11:	if (j) {
								area_var_list.push_back("Generation Cost (k$)");
								var_index_map.insert(make_pair("Generation Cost (k$)", ++num_vars));
							}
							break;
							
				case 12:	if (j) {
								area_var_list.push_back("Installed Capacity (MW)");
								var_index_map.insert(make_pair("Installed Capacity (MW)", ++num_vars));
							}
							break;

				case 13:	if (j) {
								area_var_list.push_back("Available Capacity (MW)");
								var_index_map.insert(make_pair("Available Capacity (MW)", ++num_vars));  
							}
							break;

				case 14:	if (j) {
								area_var_list.push_back("Committed Capacity (MW)");
								var_index_map.insert(make_pair("Committed Capacity (MW)", ++num_vars));  
							}
							break;

				case 15:	if (j) {
								area_var_list.push_back("Reserve Margin (%)");
								var_index_map.insert(make_pair("Reserve Margin (%)", ++num_vars));
							}
							break;
							
				case 16:	if (j) {
								area_var_list.push_back("LMP Loss Component ($/MWh)");
								var_index_map.insert(make_pair("LMP Loss Component ($/MWh)", ++num_vars));
							}
							break;

				case 17:	if (j) {
								area_var_list.push_back("LMP Congestion Component ($/MWh)");
								var_index_map.insert(make_pair("LMP Congestion Component ($/MWh)", ++num_vars));
							}
							break;

				case 18:	if (j) {
								area_var_list.push_back("Delivery Factor");
								var_index_map.insert(make_pair("Delivery Factor", ++num_vars));
							}
							break;
							
				case 19:	if (j) {
								area_var_list.push_back("Pumping (MWh)");
								var_index_map.insert(make_pair("Pumping (MWh)", ++num_vars));
							}
							break;

				case 20:	if (j) {
								area_var_list.push_back("Fixed Init. Export (MWh)");
								var_index_map.insert(make_pair("Fixed Init. Export (MWh)", ++num_vars));  
							}
							break;

				case 21:	if (j) {
								area_var_list.push_back("Scheduled Export (MWh)");
								var_index_map.insert(make_pair("Scheduled Export (MWh)", ++num_vars));
							}
							break;

				case 22:	if (j) {
								area_var_list.push_back("Estimated Losses (MWh)");
								var_index_map.insert(make_pair("Estimated Losses (MWh)", ++num_vars));
							}
							break;

				// Emission Amount by type, Yanli Wei, 06/10/2010
				case 23:	if (j) {
							if (emissions_option == 0)
								break;
							else 
								for ( int i=1; i<num_emissions+1; i++)
								{
									output = emission_type_list[i-1]+" Amount";
									area_var_list.push_back((char*)(LPCTSTR)output);
									var_index_map.insert(make_pair(output, ++num_vars));
								}
							}
							break;

				// Emission Cost by type, Yanli Wei, 06/10/2010
				case 24:	if (j) {
							if (emissions_option == 0)
								break;
							else 
								for ( int i=1; i<num_emissions+1; i++)
								{
									output = emission_type_list[i-1]+" Cost";
									area_var_list.push_back((char*)(LPCTSTR)output);
									var_index_map.insert(make_pair(output, ++num_vars));
								}
							}
							break;

				// AS Served Requirement, Yanli Wei, 06/10/2010			
				case 25:	if (j) {
							if (num_ancs == 0)
								break;
							else 
								for ( int i=1; i<num_ancs+1; i++)
								{
									output = AS_type_list[i-1] + " Requirement";
									area_var_list.push_back((char*)(LPCTSTR)output);
									var_index_map.insert(make_pair(output, ++num_vars));
								}
							}
							break;

				// AS Price, Yanli Wei, 06/10/2010
				case 26:	if (j) {
							if (num_ancs == 0)
								break;
							else 
								for ( int i=1; i<num_ancs+1; i++)
								{
									output = AS_type_list[i-1] + " Price";
									area_var_list.push_back((char*)(LPCTSTR)output);
									var_index_map.insert(make_pair(output, ++num_vars));
								}
							}
							break;

				// AS Revenue, Yanli Wei, 06/10/2010				
				case 27:	if (j) {
							if (num_ancs == 0)
								break;
							else 
								for ( int i=1; i<num_ancs+1; i++)
								{
									output = AS_type_list[i-1] + " Revenue";
									area_var_list.push_back((char*)(LPCTSTR)output);
									var_index_map.insert(make_pair(output, ++num_vars));
								}
							}
							break;
			}
		}

}

/*
 *	return area variable list
 */
char ** area_reader::get_area_var_list()
{
	if (area_var_list.size()>0)
		return &area_var_list.front();
	else
		return NULL;
}

/*
 *	return area variable list size
 */
int area_reader::get_var_list_size()
{
	return num_vars;
}

/*
 *	read area info from binary file
 */

void area_reader::read_area_info(int f_handler, long * num, vector<area_info> * info_list, map <CString, int> * info_map)
{
	area_info area;
	CString info_key;
	for (int i=0; i< *num; i++)
	{
		lseek(f_handler, i*AREA_INFO_HEADER_SIZE + AREA_INFO_HEADER_OFFSET, SEEK_SET);
		read(f_handler, &area, sizeof(area));
		info_list->push_back(area);
		info_key = CString(area.AreaName) + "|" + CString(area.RegionName);
		info_map->insert(make_pair(info_key, i+1));
	}
}

/*
 *	return area info list
 */

area_info * area_reader::get_area_info_list ()
{
	return &hourly_area_info_list.front();
}

/*
 *	return area info list size
 */

int area_reader::get_area_info_list_size()
{
	return hourly_area_info_list.size();
}

/*
 *	return area var list size
 */

int area_reader::get_area_var_list_size()
{
	return num_vars;
}

/*
 * return lookup area index by its name
 */

int area_reader::get_area_index(char * RegionName, map <CString, int> * info_map)
{
	return (*info_map)[CString(RegionName)];
}

/*
 * return binary file offset 
 * input area index, which hour and variable index
 */
unsigned long int area_reader::get_hourly_var_offset(int area_index, unsigned long area_hrs, int var_index)
{

	if (area_index==0 || area_hrs==0 || var_index ==0)
		return -1;
	int size_area_var = num_vars * sizeof (float);
	int area_hourly_start_offset = AREA_INFO_HEADER_OFFSET + hourly_num_area * AREA_INFO_HEADER_SIZE;	
	unsigned long int area_hourly_offset = size_area_var*hourly_num_area*(area_hrs-1) + (area_index-1)*size_area_var;
	int var_offset = (var_index-1)*sizeof(float);
	return area_hourly_start_offset + area_hourly_offset + var_offset;
}

float area_reader::get_area_var(char *Area_name, char* Region_name, char *var_name, unsigned long area_hrs)
{
		int area_index = hourly_area_index_map[CString(Area_name)+"|"+CString(Region_name)];
		int var_index = var_index_map[CString(var_name)];
		if ( area_index == 0 || var_index == 0)
			return -1;
		unsigned long offsetVal = get_hourly_var_offset(area_index, area_hrs, var_index);
		return get_offset_value(offsetVal);
}

float * area_reader::getAllHourlyVal(char* AreaName, char* RegionName, unsigned long area_hrs)
{
	float * val;
	val = (float*)0;
	int area_index = hourly_area_index_map[CString(AreaName)+"|"+CString(RegionName)];
	int var_index = var_index_map[area_var_list[0]];
	
	if ( area_index == 0 || var_index == 0)/* Added to check the area name and region name validity */ 
		return (float*)0;                  /* Revised by Yanli Wei */

	unsigned long offsetval = get_hourly_var_offset(area_index, area_hrs, var_index);
	val = (float*) calloc(num_vars, sizeof(float));
	lseek(file_Handle, offsetval, SEEK_SET);
	read(file_Handle, val, sizeof(float)*num_vars);
	return val;
}

unsigned long area_reader::get_summary_data_offset(int area_index)
{	
	cout<<"area index "<<area_index<<endl;
	if (area_index==0)
		return -1;
	int size_summary_data = NUM_SUMMARY_DATA * sizeof (float);
	int summary_data_start_offset = AREA_INFO_HEADER_OFFSET + hourly_num_area * AREA_INFO_HEADER_SIZE;
	return summary_data_start_offset + size_summary_data * (area_index-1);
}

area_yearly_data area_reader::get_area_yearly_data(CString AreaName, CString RegionName)
{
	area_yearly_data data={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; // 15 variables, Yanli Wei, 06/14/2010
	int offset = get_summary_data_offset(hourly_area_index_map[CString(AreaName)+"|"+CString(RegionName)]);
	cout<<offset<<endl;
	if ( offset == -1)
		return data;
	lseek(summary_file_Handle, offset, SEEK_SET);
	read(summary_file_Handle, &data, sizeof(area_yearly_data));	
	return data;
}



area_reader::~area_reader ()
{
	if (summary_file_Handle >0) 
	{
		if (close (summary_file_Handle) == 0)
		{
			printf ("Close yearly summary file succeeded.\n");
		}
		else 
		{
			printf ("Close yearly summary file failed.\n");
			switch (errno) 
			{
				case EBADF:  printf ("File not open.\n"); break;
				default:     printf ("Unknown error.\n"); break;
			}
		}
	}
}